2 用 filter() 筛选行
2.1 按给定的逻辑判断筛选出符合要求的子数据集, 类似于 base::subset() 函数
filter(flights, month == 1, day == 1)
#> # A tibble: 842 × 19
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 1 517 515 2 830
#> 2 2013 1 1 533 529 4 850
#> 3 2013 1 1 542 540 2 923
#> 4 2013 1 1 544 545 -1 1004
#> 5 2013 1 1 554 600 -6 812
#> 6 2013 1 1 554 558 -4 740
#> # ... with 836 more rows, and 12 more variables: sched_arr_time <int>,
#> # arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> # minute <dbl>, time_hour <dttm>
(dec25 <- filter(flights, month == 12, day == 25))
#> # A tibble: 719 × 19
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 12 25 456 500 -4 649
#> 2 2013 12 25 524 515 9 805
#> 3 2013 12 25 542 540 2 832
#> 4 2013 12 25 546 550 -4 1022
#> 5 2013 12 25 556 600 -4 730
#> 6 2013 12 25 557 600 -3 743
#> # ... with 713 more rows, and 12 more variables: sched_arr_time <int>,
#> # arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> # minute <dbl>, time_hour <dttm>
2.2 对某个变量选取两个或以上的值
filter(flights, month == 11 | month == 12)
filter(flights, month %in% c(11, 12))
2.3 缺失值
NA (“not availables”) 代表缺失值,在计算中有“传染性”:对 NA 进行任意操作,都会返回 NA。
NA > 5
[1] NA
10 == NA
[1] NA
NA + 10
[1] NA
NA / 2
[1] NA
NA == NA
[1] NA
x <- NA
y <- NA
x == y
[1] NA
is.na(x)
[1] TRUE
df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
#> # A tibble: 1 × 1
#> x
#> <dbl>
#> 1 3
filter() 会排除 False 和 NA 的行,仅仅返回结果为 True 的行。如果想要保留缺失值,需要进行显式声明
filter(df, is.na(x) | x > 1)
#> # A tibble: 2 × 1
#> x
#> <dbl>
#> 1 NA
#> 2 3
2.4 between()
df <- tibble(x = c(1, 2, 2, 3, 4))
filter(df, between(x, 1, 3))
#> # A tibble: 4 × 1
#> x
#> <dbl>
#> 1 1
#> 2 2
#> 3 2
#> 4 3
3 用 arrange() 排列行
arrange(flights, year, month, day)
#> # A tibble: 336,776 × 19
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 1 517 515 2 830
#> 2 2013 1 1 533 529 4 850
#> 3 2013 1 1 542 540 2 923
#> 4 2013 1 1 544 545 -1 1004
#> 5 2013 1 1 554 600 -6 812
#> 6 2013 1 1 554 558 -4 740
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> # sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
arrange(flights, desc(arr_delay))
#> # A tibble: 336,776 × 19
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 9 641 900 1301 1242
#> 2 2013 6 15 1432 1935 1137 1607
#> 3 2013 1 10 1121 1635 1126 1239
#> 4 2013 9 20 1139 1845 1014 1457
#> 5 2013 7 22 845 1600 1005 1044
#> 6 2013 4 10 1100 1900 960 1342
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> # sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
df <- tibble(x = c(5, 2, NA))
arrange(df, x)
#> # A tibble: 3 × 1
#> x
#> <dbl>
#> 1 2
#> 2 5
#> 3 NA
arrange(df, desc(x))
#> # A tibble: 3 × 1
#> x
#> <dbl>
#> 1 5
#> 2 2
#> 3 NA
4 用 select() 筛选列
4.1 基本用法
select(flights, year, month, day)
#> # A tibble: 336,776 × 3
#> year month day
#> <int> <int> <int>
#> 1 2013 1 1
#> 2 2013 1 1
#> 3 2013 1 1
#> 4 2013 1 1
#> 5 2013 1 1
#> 6 2013 1 1
#> # ... with 3.368e+05 more rows
select(flights, year:day)
#> # A tibble: 336,776 × 3
#> year month day
#> <int> <int> <int>
#> 1 2013 1 1
#> 2 2013 1 1
#> 3 2013 1 1
#> 4 2013 1 1
#> 5 2013 1 1
#> 6 2013 1 1
#> # ... with 3.368e+05 more rows
- 选择除year和day之间的列以外的所有列(包括)
select(flights, -(year:day))
#> # A tibble: 336,776 × 16
#> dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
#> <int> <int> <dbl> <int> <int> <dbl>
#> 1 517 515 2 830 819 11
#> 2 533 529 4 850 830 20
#> 3 542 540 2 923 850 33
#> 4 544 545 -1 1004 1022 -18
#> 5 554 600 -6 812 837 -25
#> 6 554 558 -4 740 728 12
#> # ... with 3.368e+05 more rows, and 10 more variables: carrier <chr>,
#> # flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
4.2 Helper Functions
starts_with(x, ignore.case = TRUE): names starts with x.
ends_with(x, ignore.case = TRUE): names ends in x.
contains(x, ignore.case = TRUE): selects all variables whose name contains x.
matches(x, ignore.case = TRUE): selects all variables whose name matches the regular expression x.
num_range("x", 1:5, width = 2): selects all variables (numerically) from x01 to x05.
one_of("x", "y", "z"): selects variables provided in a character vector.
everything(): selects all variables.
4.3 利用 everything() 将列移到最前面
select(flights, time_hour, air_time, everything())
#> # A tibble: 336,776 × 19
#> time_hour air_time year month day dep_time sched_dep_time
#> <dttm> <dbl> <int> <int> <int> <int> <int>
#> 1 2013-01-01 05:00:00 227 2013 1 1 517 515
#> 2 2013-01-01 05:00:00 227 2013 1 1 533 529
#> 3 2013-01-01 05:00:00 160 2013 1 1 542 540
#> 4 2013-01-01 05:00:00 183 2013 1 1 544 545
#> 5 2013-01-01 06:00:00 116 2013 1 1 554 600
#> 6 2013-01-01 05:00:00 150 2013 1 1 554 558
#> # ... with 3.368e+05 more rows, and 12 more variables: dep_delay <dbl>,
#> # arr_time <int>, sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#> # flight <int>, tailnum <chr>, origin <chr>, dest <chr>, distance <dbl>,
#> # hour <dbl>, minute <dbl>
4.4 rename() 函数
rename(flights, tail_num = tailnum)
#> # A tibble: 336,776 × 19
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 1 517 515 2 830
#> 2 2013 1 1 533 529 4 850
#> 3 2013 1 1 542 540 2 923
#> 4 2013 1 1 544 545 -1 1004
#> 5 2013 1 1 554 600 -6 812
#> 6 2013 1 1 554 558 -4 740
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> # sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> # tail_num <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
5 用 mutate() 添加列
5.1 基本用法
flights_sml <- select(flights,
year:day,
ends_with("delay"),
distance,
air_time
)
mutate(flights_sml,
gain = arr_delay - dep_delay,
speed = distance / air_time * 60
)
#> # A tibble: 336,776 × 9
#> year month day dep_delay arr_delay distance air_time gain speed
#> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013 1 1 2 11 1400 227 9 370
#> 2 2013 1 1 4 20 1416 227 16 374
#> 3 2013 1 1 2 33 1089 160 31 408
#> 4 2013 1 1 -1 -18 1576 183 -17 517
#> 5 2013 1 1 -6 -25 762 116 -19 394
#> 6 2013 1 1 -4 12 719 150 16 288
#> # ... with 3.368e+05 more rows
mutate(flights_sml,
gain = arr_delay - dep_delay,
hours = air_time / 60,
gain_per_hour = gain / hours
)
#> # A tibble: 336,776 × 10
#> year month day dep_delay arr_delay distance air_time gain hours
#> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013 1 1 2 11 1400 227 9 3.78
#> 2 2013 1 1 4 20 1416 227 16 3.78
#> 3 2013 1 1 2 33 1089 160 31 2.67
#> 4 2013 1 1 -1 -18 1576 183 -17 3.05
#> 5 2013 1 1 -6 -25 762 116 -19 1.93
#> 6 2013 1 1 -4 12 719 150 16 2.50
#> # ... with 3.368e+05 more rows, and 1 more variables: gain_per_hour <dbl>
transmute(flights,
gain = arr_delay - dep_delay,
hours = air_time / 60,
gain_per_hour = gain / hours
)
#> # A tibble: 336,776 × 3
#> gain hours gain_per_hour
#> <dbl> <dbl> <dbl>
#> 1 9 3.78 2.38
#> 2 16 3.78 4.23
#> 3 31 2.67 11.62
#> 4 -17 3.05 -5.57
#> 5 -19 1.93 -9.83
#> 6 16 2.50 6.40
#> # ... with 3.368e+05 more rows
5.2 可以用于计算新变量的向量化运算符
Arithmetic operators: +, -, *, /, ^.
Modular arithmetic: %/% (integer division) and %% (remainder).
transmute(flights,
dep_time,
hour = dep_time %/% 100,
minute = dep_time %% 100
)
#> # A tibble: 336,776 × 3
#> dep_time hour minute
#> <int> <dbl> <dbl>
#> 1 517 5 17
#> 2 533 5 33
#> 3 542 5 42
#> 4 544 5 44
#> 5 554 5 54
#> 6 554 5 54
#> # ... with 3.368e+05 more rows
Logs: log(), log2(), log10().
Offsets: lead() and lag() allow you to refer to leading or lagging values.
(x <- 1:10)
[1] 1 2 3 4 5 6 7 8 9 10
lag(x)
[1] NA 1 2 3 4 5 6 7 8 9
lead(x)
[1] 2 3 4 5 6 7 8 9 10 NA
# compute running differences
x - lag(x)
[1] NA 1 1 1 1 1 1 1 1 1
# find when values change
x != lag(x)
[1] NA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
- Cumulative and rolling aggregates:
cumsum(), cumprod(), cummin(), cummax(), cummean().
If you need rolling aggregates (i.e. a sum computed over a rolling window), try the RcppRoll package.
x
[1] 1 2 3 4 5 6 7 8 9 10
cumsum(x)
[1] 1 3 6 10 15 21 28 36 45 55
cummean(x)
[1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5
Logical comparisons, <, <=, >, >=, !=.
Ranking: min_rank(), row_number(), dense_rank(), percent_rank(), cume_dist(), ntile().
(y <- c(1, 2, 2, NA, 3, 4))
[1] 1 2 2 NA 3 4
min_rank(y)
[1] 1 2 2 NA 4 5
min_rank(desc(y))
[1] 5 3 3 NA 2 1
row_number(y)
[1] 1 2 3 NA 4 5
dense_rank(y)
[1] 1 2 2 NA 3 4
percent_rank(y)
[1] 0.00 0.25 0.25 NA 0.75 1.00
cume_dist(y)
[1] 0.2 0.6 0.6 NA 0.8 1.0
6 用 summarise() 计算分组统计量
6.1 group_by() 和 summarise() 联合使用,计算分组统计量
summarise(flights, delay = mean(dep_delay, na.rm = TRUE))
#> # A tibble: 1 × 1
#> delay
#> <dbl>
#> 1 12.6
by_day <- group_by(flights, year, month, day)
summarise(by_day, delay = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day delay
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.55
#> 2 2013 1 2 13.86
#> 3 2013 1 3 10.99
#> 4 2013 1 4 8.95
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
6.2 管道操作符 %>%
- 探索对于不同地点,平均飞行距离与平均延误时间之间的关系。可以发现,平均飞行距离为750英里时,平均延误时间达到峰值,可能是由于更长的飞行距离,为弥补延误提供了可能。
by_dest <- group_by(flights, dest)
delay <- summarise(by_dest,
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
)
(delay <- filter(delay, count > 20, dest != "HNL"))
#> # A tibble: 96 × 4
#> dest count dist delay
#> <chr> <int> <dbl> <dbl>
#> 1 ABQ 254 1826.0000 4.381890
#> 2 ACK 265 199.0000 4.852273
#> 3 ALB 439 143.0000 14.397129
#> 4 ATL 17215 757.1082 11.300113
#> 5 AUS 2439 1514.2530 6.019909
#> 6 AVL 275 583.5818 8.003831
#> 7 BDL 443 116.0000 7.048544
#> 8 BGR 375 378.0000 8.027933
#> 9 BHM 297 865.9966 16.877323
#> 10 BNA 6333 758.2135 11.812459
#> # ... with 86 more rows
ggplot(data = delay, mapping = aes(x = dist, y = delay)) +
geom_point(aes(size = count), alpha = 1/3) +
geom_smooth(se = FALSE)

- 数据预处理涉及3个步骤:
- 依据目的地分组
- 计算分组后的平均飞行距离、平均延误时间和航班数
- 过滤掉夏威夷机场(平均飞行距离是其他机场的2倍以上)和航班数过少的目的地
- 使用管道操作符
%>% 完成以上3个步骤
delays <- flights %>%
group_by(dest) %>%
summarise(
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
) %>%
filter(count > 20, dest != "HNL")
6.3 缺失值
flights %>%
group_by(year, month, day) %>%
summarise(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 NA
#> 2 2013 1 2 NA
#> 3 2013 1 3 NA
#> 4 2013 1 4 NA
#> 5 2013 1 5 NA
#> 6 2013 1 6 NA
#> # ... with 359 more rows
flights %>%
group_by(year, month, day) %>%
summarise(mean = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.55
#> 2 2013 1 2 13.86
#> 3 2013 1 3 10.99
#> 4 2013 1 4 8.95
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
not_cancelled <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay))
not_cancelled %>%
group_by(year, month, day) %>%
summarise(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.44
#> 2 2013 1 2 13.68
#> 3 2013 1 3 10.91
#> 4 2013 1 4 8.97
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
6.4 计数(count)
在计算分组统计量的时候,需要考虑组内样本的个数(n())、非缺失值的个数(sum(!is.na(x)))以及分组的个数
- 用
tailnum 区分飞机,用核密度图分析飞机的平均延误时间分布情况
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarise(
delay = mean(arr_delay)
)
delays
#> # A tibble: 4,037 × 2
#> tailnum delay
#> <chr> <dbl>
#> 1 D942DN 31.5000000
#> 2 N0EGMQ 9.9829545
#> 3 N10156 12.7172414
#> 4 N102UW 2.9375000
#> 5 N103US -6.9347826
#> 6 N104UW 1.8043478
#> 7 N10575 20.6914498
#> 8 N105UW -0.2666667
#> 9 N107US -5.7317073
#> 10 N108UW -1.2500000
#> # ... with 4,027 more rows
ggplot(data = delays, mapping = aes(x = delay)) +
geom_freqpoly(binwidth = 10)

- 用
n() 计算组内样本个数,从散点图可以看出,飞行次数少的飞机,平均延误时间的变异程度更大
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarise(
delay = mean(arr_delay, na.rm = TRUE),
n = n()
)
delays
#> # A tibble: 4,037 × 3
#> tailnum delay n
#> <chr> <dbl> <int>
#> 1 D942DN 31.5000000 4
#> 2 N0EGMQ 9.9829545 352
#> 3 N10156 12.7172414 145
#> 4 N102UW 2.9375000 48
#> 5 N103US -6.9347826 46
#> 6 N104UW 1.8043478 46
#> 7 N10575 20.6914498 269
#> 8 N105UW -0.2666667 45
#> 9 N107US -5.7317073 41
#> 10 N108UW -1.2500000 60
#> # ... with 4,027 more rows
ggplot(data = delays, mapping = aes(x = n, y = delay)) +
geom_point(alpha = 1/10)

- 利用
filter() 筛选出飞行次数大于25的飞机,分析它们的延误情况

ba 代表击打成功率, ab 代表击打次数,击打成功率与击打数正相关,可能是因为球队倾向于让成功率高的球员拥有更多出场机会
# Convert to a tibble so it prints nicely
batting <- as_tibble(Lahman::Batting)
batters <- batting %>%
group_by(playerID) %>%
summarise(
ba = sum(H, na.rm = TRUE) / sum(AB, na.rm = TRUE),
ab = sum(AB, na.rm = TRUE)
)
batters %>%
filter(ab > 100) %>%
ggplot(mapping = aes(x = ab, y = ba)) +
geom_point() +
geom_smooth(se = FALSE)

- 依据
ba 进行降序排列,可以看出,击打成功率最高的球员,击打次数只有一次,纯粹是由于运气而非技术
batters %>%
arrange(desc(ba))
#> # A tibble: 18,659 × 3
#> playerID ba ab
#> <chr> <dbl> <int>
#> 1 abramge01 1 1
#> 2 banisje01 1 1
#> 3 bartocl01 1 1
#> 4 bassdo01 1 1
#> 5 birasst01 1 2
#> 6 bruneju01 1 1
#> # ... with 1.865e+04 more rows
6.5 聚合统计函数
- Measures of location:
mean(x), median(x).
not_cancelled %>%
group_by(year, month, day) %>%
summarise(
avg_delay1 = mean(arr_delay),
avg_delay2 = mean(arr_delay[arr_delay > 0]) # the average positive delay
)
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#>
#> year month day avg_delay1 avg_delay2
#> <int> <int> <int> <dbl> <dbl>
#> 1 2013 1 1 12.65 32.5
#> 2 2013 1 2 12.69 32.0
#> 3 2013 1 3 5.73 27.7
#> 4 2013 1 4 -1.93 28.3
#> 5 2013 1 5 -1.53 22.6
#> 6 2013 1 6 4.24 24.4
#> # ... with 359 more rows
- Measures of spread:
sd(x), IQR(x), mad(x).
# Why is distance to some destinations more variable than to others?
not_cancelled %>%
group_by(dest) %>%
summarise(distance_sd = sd(distance)) %>%
arrange(desc(distance_sd))
#> # A tibble: 104 × 2
#> dest distance_sd
#> <chr> <dbl>
#> 1 EGE 10.54
#> 2 SAN 10.35
#> 3 SFO 10.22
#> 4 HNL 10.00
#> 5 SEA 9.98
#> 6 LAS 9.91
#> # ... with 98 more rows
- Measures of rank:
min(x), quantile(x, 0.25), max(x).
# When do the first and last flights leave each day?
not_cancelled %>%
group_by(year, month, day) %>%
summarise(
first = min(dep_time),
last = max(dep_time)
)
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#>
#> year month day first last
#> <int> <int> <int> <int> <int>
#> 1 2013 1 1 517 2356
#> 2 2013 1 2 42 2354
#> 3 2013 1 3 32 2349
#> 4 2013 1 4 25 2358
#> 5 2013 1 5 14 2357
#> 6 2013 1 6 16 2355
#> # ... with 359 more rows
- Measures of position:
first(x), nth(x, 2), last(x).
not_cancelled %>%
group_by(year, month, day) %>%
summarise(
first_dep = first(dep_time),
last_dep = last(dep_time)
)
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#>
#> year month day first_dep last_dep
#> <int> <int> <int> <int> <int>
#> 1 2013 1 1 517 2356
#> 2 2013 1 2 42 2354
#> 3 2013 1 3 32 2349
#> 4 2013 1 4 25 2358
#> 5 2013 1 5 14 2357
#> 6 2013 1 6 16 2355
#> # ... with 359 more rows
同样的效果,可以通过以下方法实现,并且会保留所有的变量,注意 mutate(), min_rank, filter() 在这里的作用
not_cancelled %>%
group_by(year, month, day) %>%
mutate(r = min_rank(desc(dep_time))) %>%
filter(r %in% range(r))
#> Source: local data frame [770 x 20]
#> Groups: year, month, day [365]
#>
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 1 517 515 2 830
#> 2 2013 1 1 2356 2359 -3 425
#> 3 2013 1 2 42 2359 43 518
#> 4 2013 1 2 2354 2359 -5 413
#> 5 2013 1 3 32 2359 33 504
#> 6 2013 1 3 2349 2359 -10 434
#> # ... with 764 more rows, and 13 more variables: sched_arr_time <int>,
#> # arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> # minute <dbl>, time_hour <dttm>, r <int>
- Counts:
count(), n(), sum(!is.na(x)), n_distinct(x).
# Which destinations have the most carriers?
not_cancelled %>%
group_by(dest) %>%
summarise(carriers = n_distinct(carrier)) %>%
arrange(desc(carriers))
#> # A tibble: 104 × 2
#> dest carriers
#> <chr> <int>
#> 1 ATL 7
#> 2 BOS 7
#> 3 CLT 7
#> 4 ORD 7
#> 5 TPA 7
#> 6 AUS 6
#> # ... with 98 more rows
强大的 count() 函数,此处计算每个机场作为目的地的航班数
not_cancelled %>%
count(dest)
#> # A tibble: 104 × 2
#> dest n
#> <chr> <int>
#> 1 ABQ 254
#> 2 ACK 264
#> 3 ALB 418
#> 4 ANC 8
#> 5 ATL 16837
#> 6 AUS 2411
#> # ... with 98 more rows
count() 可以用于加权计数,此处计算每架飞机的总飞行里程
not_cancelled %>%
count(tailnum, wt = distance)
#> # A tibble: 4,037 × 2
#> tailnum n
#> <chr> <dbl>
#> 1 D942DN 3418
#> 2 N0EGMQ 239143
#> 3 N10156 109664
#> 4 N102UW 25722
#> 5 N103US 24619
#> 6 N104UW 24616
#> # ... with 4,031 more rows
- Counts and proportions of logical values:
sum(x > 10), mean(y == 0). sum(x) gives the number of TRUEs in x, and mean(x) gives the proportion.
# How many flights left before 5am? (these usually indicate delayed
# flights from the previous day)
not_cancelled %>%
group_by(year, month, day) %>%
summarise(n_early = sum(dep_time < 500))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day n_early
#> <int> <int> <int> <int>
#> 1 2013 1 1 0
#> 2 2013 1 2 3
#> 3 2013 1 3 4
#> 4 2013 1 4 3
#> 5 2013 1 5 3
#> 6 2013 1 6 2
#> # ... with 359 more rows
# What proportion of flights are delayed by more than an hour?
not_cancelled %>%
group_by(year, month, day) %>%
summarise(hour_perc = mean(arr_delay > 60))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day hour_perc
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 0.0722
#> 2 2013 1 2 0.0851
#> 3 2013 1 3 0.0567
#> 4 2013 1 4 0.0396
#> 5 2013 1 5 0.0349
#> 6 2013 1 6 0.0470
#> # ... with 359 more rows
6.6 依据多个变量进行分组
创建依据多个变量的分组后,每一次 summarise都会剥离一层分组变量
- 依据
year, month, day 三个变量分组
daily <- group_by(flights, year, month, day)
(per_day <- summarise(daily, flights = n()))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day flights
#> <int> <int> <int> <int>
#> 1 2013 1 1 842
#> 2 2013 1 2 943
#> 3 2013 1 3 914
#> 4 2013 1 4 915
#> 5 2013 1 5 720
#> 6 2013 1 6 832
#> # ... with 359 more rows
(per_month <- summarise(per_day, flights = sum(flights)))
#> Source: local data frame [12 x 3]
#> Groups: year [?]
#>
#> year month flights
#> <int> <int> <int>
#> 1 2013 1 27004
#> 2 2013 2 24951
#> 3 2013 3 28834
#> 4 2013 4 28330
#> 5 2013 5 28796
#> 6 2013 6 28243
#> # ... with 6 more rows
(per_year <- summarise(per_month, flights = sum(flights)))
#> # A tibble: 1 × 2
#> year flights
#> <int> <int>
#> 1 2013 336776
6.7 取消分组
daily %>%
ungroup() %>% # no longer grouped by date
summarise(flights = n()) # all flights
#> # A tibble: 1 × 1
#> flights
#> <int>
#> 1 336776
7 分组变换(mutate(), filter())
flights_sml %>%
group_by(year, month, day) %>%
filter(rank(desc(arr_delay)) < 10)
#> Source: local data frame [3,306 x 7]
#> Groups: year, month, day [365]
#>
#> year month day dep_delay arr_delay distance air_time
#> <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 2013 1 1 853 851 184 41
#> 2 2013 1 1 290 338 1134 213
#> 3 2013 1 1 260 263 266 46
#> 4 2013 1 1 157 174 213 60
#> 5 2013 1 1 216 222 708 121
#> 6 2013 1 1 255 250 589 115
#> # ... with 3,300 more rows
popular_dests <- flights %>%
group_by(dest) %>%
filter(n() > 365)
popular_dests
#> Source: local data frame [332,577 x 19]
#> Groups: dest [77]
#>
#> year month day dep_time sched_dep_time dep_delay arr_time
#> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 2013 1 1 517 515 2 830
#> 2 2013 1 1 533 529 4 850
#> 3 2013 1 1 542 540 2 923
#> 4 2013 1 1 544 545 -1 1004
#> 5 2013 1 1 554 600 -6 812
#> 6 2013 1 1 554 558 -4 740
#> # ... with 3.326e+05 more rows, and 12 more variables:
#> # sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
popular_dests %>%
filter(arr_delay > 0) %>%
mutate(prop_delay = arr_delay / sum(arr_delay)) %>%
select(year:day, dest, arr_delay, prop_delay)
#> Source: local data frame [131,106 x 6]
#> Groups: dest [77]
#>
#> year month day dest arr_delay prop_delay
#> <int> <int> <int> <chr> <dbl> <dbl>
#> 1 2013 1 1 IAH 11 1.11e-04
#> 2 2013 1 1 IAH 20 2.01e-04
#> 3 2013 1 1 MIA 33 2.35e-04
#> 4 2013 1 1 ORD 12 4.24e-05
#> 5 2013 1 1 FLL 19 9.38e-05
#> 6 2013 1 1 ORD 8 2.83e-05
#> # ... with 1.311e+05 more rows
LS0tDQp0aXRsZTogIsr9vt3Xqru7Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyDEv8K8DQorIDEgx7DM4de8sbgNCiAgICArIDEuMSDU2MjrsPwNCiAgICArIDEuMiBgZmxpZ2h0c2Agyv2+3byvDQogICAgKyAxLjMgyv2+3cDg0M296cncDQogICAgKyAxLjQgYGRwbHlyYCC7+bShDQorIDIg08MgYGZpbHRlcigpYCDJuNGh0NANCiAgICArIDIuMSCwtLj4tqi1xMLfvK3F0LbPybjRobP2t/u6z9Kqx/O1xNfTyv2+3byvDQogICAgKyAyLjIgttTEs7j2seTBv9GhyKHBvbj2u/LS1MnPtcTWtQ0KICAgICsgMi4zIMixyqfWtQ0KICAgICsgMi40IGBiZXR3ZWVuKClgDQorIDMg08MgYGFycmFuZ2UoKWAgxcXB0NDQDQorIDQg08MgYHNlbGVjdCgpYCDJuNGhwdANCiAgICArIDQuMSC7+bG+08O3qA0KICAgICsgNC4yIEhlbHBlciBGdW5jdGlvbnMNCiAgICArIDQuMyDA+9PDIGBldmVyeXRoaW5nKClgIL2rwdDSxrW91+7HsMPmDQogICAgKyA0LjQgYHJlbmFtZSgpYCC6r8r9DQorIDUg08MgYG11dGF0ZSgpYCDM7bzTwdANCiAgICArIDUuMSC7+bG+08O3qA0KICAgICsgNS4yIL/J0tTTw9PavMbL49DCseTBv7XEz/LBv7uv1MvL47f7DQorIDYg08MgYHN1bW1hcmlzZSgpYCC8xsvjt9bX6c2zvMbBvw0KICAgICsgNi4xIGBncm91cF9ieSgpYCC6zSBgc3VtbWFyaXNlKClgIMGqus/KudPDo6y8xsvjt9bX6c2zvMbBvw0KICAgICsgNi4yILnctcCy2df3t/sgYCU+JWANCiAgICArIDYuMyDIscqn1rUNCiAgICArIDYuNCC8xsr9o6hgY291bnRgo6kNCiAgICArIDYuNSC+27rPzbO8xrqvyv0NCiAgICArIDYuNiDSwL7dtuC49rHkwb+9+NDQt9bX6Q0KICAgICsgNi43IMihz/u31tfpDQorIDcgt9bX6bHku7ujqGBtdXRhdGUoKWAsIGBmaWx0ZXIoKWCjqQ0KDQojIDEgx7DM4de8sbgNCiMjIDEuMSDU2MjrsPwNCmBgYHtyfQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQojIyAxLjIgYGZsaWdodHNgIMr9vt28ryAgDQorIGBmbGlnaHRzYCDK/b7dvK/S1CBgdGliYmxlYCDQzsq9tOa0og0KYGBge3J9DQpmbGlnaHRzDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxOQ0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfdGltZSBzY2hlZF9kZXBfdGltZSBkZXBfZGVsYXkgYXJyX3RpbWUNCiM+ICAgPGludD4gPGludD4gPGludD4gICAgPGludD4gICAgICAgICAgPGludD4gICAgIDxkYmw+ICAgIDxpbnQ+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgNTE3ICAgICAgICAgICAgNTE1ICAgICAgICAgMiAgICAgIDgzMA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUzMyAgICAgICAgICAgIDUyOSAgICAgICAgIDQgICAgICA4NTANCiM+IDMgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDIgICAgICAgICAgICA1NDAgICAgICAgICAyICAgICAgOTIzDQojPiA0ICAyMDEzICAgICAxICAgICAxICAgICAgNTQ0ICAgICAgICAgICAgNTQ1ICAgICAgICAtMSAgICAgMTAwNA0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDYwMCAgICAgICAgLTYgICAgICA4MTINCiM+IDYgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA1NTggICAgICAgIC00ICAgICAgNzQwDQojPiAjIC4uLiB3aXRoIDMuMzY4ZSswNSBtb3JlIHJvd3MsIGFuZCAxMiBtb3JlIHZhcmlhYmxlczoNCiM+ICMgICBzY2hlZF9hcnJfdGltZSA8aW50PiwgYXJyX2RlbGF5IDxkYmw+LCBjYXJyaWVyIDxjaHI+LCBmbGlnaHQgPGludD4sDQojPiAjICAgdGFpbG51bSA8Y2hyPiwgb3JpZ2luIDxjaHI+LCBkZXN0IDxjaHI+LCBhaXJfdGltZSA8ZGJsPiwNCiM+ICMgICBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwgbWludXRlIDxkYmw+LCB0aW1lX2hvdXIgPGR0dG0+DQpgYGANCg0KKyDKudPDIGBWaWV3YCC/ydLUuduy7M3q1fu1xCBgZmxpZ2h0c2Agyv2+3byvICANCmBgYA0KVmlldyhmbGlnaHRzKQ0KYGBgDQoNCiMjIDEuMyDK/b7dwODQzb3pydwNCg0KKyBgaW50YCBzdGFuZHMgZm9yIGludGVnZXJzLg0KDQorIGBkYmxgIHN0YW5kcyBmb3IgZG91Ymxlcywgb3IgcmVhbCBudW1iZXJzLg0KDQorIGBjaHJgIHN0YW5kcyBmb3IgY2hhcmFjdGVyIHZlY3RvcnMsIG9yIHN0cmluZ3MuDQoNCisgYGR0dG1gIHN0YW5kcyBmb3IgZGF0ZS10aW1lcyAoYSBkYXRlICsgYSB0aW1lKS4NCg0KKyBgbGdsYCBzdGFuZHMgZm9yIGxvZ2ljYWwsIHZlY3RvcnMgdGhhdCBjb250YWluIG9ubHkgVFJVRSBvciBGQUxTRS4NCg0KKyBgZmN0cmAgc3RhbmRzIGZvciBmYWN0b3JzLCB3aGljaCBSIHVzZXMgdG8gcmVwcmVzZW50IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGZpeGVkIHBvc3NpYmxlIHZhbHVlcy4NCg0KKyBgZGF0ZWAgc3RhbmRzIGZvciBkYXRlcy4NCg0KIyMgMS40IGBkcGx5cmAgu/m0oQ0KvdPPwsC0o6y9q7vhvdO0pbW9NdbWusvQxLXEIGBkcGx5cmAguq/K/Q0KDQorIFBpY2sgb2JzZXJ2YXRpb25zIGJ5IHRoZWlyIHZhbHVlcyBgZmlsdGVyKClgLg0KDQorIFJlb3JkZXIgdGhlIHJvd3MgYGFycmFuZ2UoKWAuDQoNCisgUGljayB2YXJpYWJsZXMgYnkgdGhlaXIgbmFtZXMgYHNlbGVjdCgpYC4NCg0KKyBDcmVhdGUgbmV3IHZhcmlhYmxlcyB3aXRoIGZ1bmN0aW9ucyBvZiBleGlzdGluZyB2YXJpYWJsZXMgYG11dGF0ZSgpYC4NCg0KKyBDb2xsYXBzZSBtYW55IHZhbHVlcyBkb3duIHRvIGEgc2luZ2xlIHN1bW1hcnkgYHN1bW1hcmlzZSgpYC4NCg0KIyAyINPDIGBmaWx0ZXIoKWAgybjRodDQICANCiMjIDIuMSCwtLj4tqi1xMLfvK3F0LbPybjRobP2t/u6z9Kqx/O1xNfTyv2+3byvLCDA4MvG09ogYmFzZTo6c3Vic2V0KCkguq/K/Q0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogODQyIKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA5MjMNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDQgICAgICAgICAgICA1NDUgICAgICAgIC0xICAgICAxMDA0DQojPiA1ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMg0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDU1OCAgICAgICAgLTQgICAgICA3NDANCiM+ICMgLi4uIHdpdGggODM2IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQpgYGB7cn0NCihkZWMyNSA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMTIsIGRheSA9PSAyNSkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogNzE5IKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgMTIgICAgMjUgICAgICA0NTYgICAgICAgICAgICA1MDAgICAgICAgIC00ICAgICAgNjQ5DQojPiAyICAyMDEzICAgIDEyICAgIDI1ICAgICAgNTI0ICAgICAgICAgICAgNTE1ICAgICAgICAgOSAgICAgIDgwNQ0KIz4gMyAgMjAxMyAgICAxMiAgICAyNSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA4MzINCiM+IDQgIDIwMTMgICAgMTIgICAgMjUgICAgICA1NDYgICAgICAgICAgICA1NTAgICAgICAgIC00ICAgICAxMDIyDQojPiA1ICAyMDEzICAgIDEyICAgIDI1ICAgICAgNTU2ICAgICAgICAgICAgNjAwICAgICAgICAtNCAgICAgIDczMA0KIz4gNiAgMjAxMyAgICAxMiAgICAyNSAgICAgIDU1NyAgICAgICAgICAgIDYwMCAgICAgICAgLTMgICAgICA3NDMNCiM+ICMgLi4uIHdpdGggNzEzIG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQojIyAyLjIgttTEs7j2seTBv9GhyKHBvbj2u/LS1MnPtcTWtQ0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMTEgfCBtb250aCA9PSAxMikNCmBgYA0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggJWluJSBjKDExLCAxMikpDQpgYGANCg0KIyMgMi4zIMixyqfWtQ0KKyBgTkFgICihsG5vdCBhdmFpbGFibGVzobEpILT6se3Iscqn1rWjrNTavMbL49bQ09ChsLSryL7Q1KGxo7q21CBgTkFgIL340NDIztListnX96Ostry74be1u9ggYE5BYKGjDQpgYGB7cn0NCk5BID4gNQ0KYGBgDQpgYGB7cn0NCjEwID09IE5BDQpgYGANCmBgYHtyfQ0KTkEgKyAxMA0KYGBgDQpgYGB7cn0NCk5BIC8gMg0KYGBgDQpgYGB7cn0NCk5BID09IE5BDQpgYGANCmBgYHtyfQ0KeCA8LSBOQQ0KeSA8LSBOQQ0KeCA9PSB5DQpgYGANCg0KKyDTwyBgaXMubmEoKWAgxdC2z8rHt/HOqsixyqfWtQ0KYGBge3J9DQppcy5uYSh4KQ0KYGBgDQoNCmBgYHtyfQ0KZGYgPC0gdGliYmxlKHggPSBjKDEsIE5BLCAzKSkNCmZpbHRlcihkZiwgeCA+IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMSChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgICAzDQpgYGANCg0KKyBgZmlsdGVyKClgILvhxcWz/SBgRmFsc2VgILrNIGBOQWAgtcTQ0KOsvfa99re1u9i94bn7zqogYFRydWVgILXE0NCho8jnufvP69KqsaPB9MixyqfWtaOs0OjSqr340NDP1Mq9yfnD9w0KYGBge3J9DQpmaWx0ZXIoZGYsIGlzLm5hKHgpIHwgeCA+IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMiChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgIE5BDQojPiAyICAgICAzDQpgYGANCg0KIyMgMi40IGBiZXR3ZWVuKClgDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYygxLCAyLCAyLCAzLCA0KSkNCmZpbHRlcihkZiwgYmV0d2Vlbih4LCAxLCAzKSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiA0IKHBIDENCiM+ICAgICAgIHgNCiM+ICAgPGRibD4NCiM+IDEgICAgIDENCiM+IDIgICAgIDINCiM+IDMgICAgIDINCiM+IDQgICAgIDMNCmBgYA0KDQojIDMg08MgYGFycmFuZ2UoKWAgxcXB0NDQDQorILC0uPi2qLXEwdDD+9LAtM621NDQvfjQ0MXF0PINCmBgYHtyfQ0KYXJyYW5nZShmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMTkNCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzANCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MzMgICAgICAgICAgICA1MjkgICAgICAgICA0ICAgICAgODUwDQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgNTQyICAgICAgICAgICAgNTQwICAgICAgICAgMiAgICAgIDkyMw0KIz4gNCAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA2MDAgICAgICAgIC02ICAgICAgODEyDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNTU4ICAgICAgICAtNCAgICAgIDc0MA0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisg08MgYGRlc2MoKWAgvfjQ0L210PLFxcHQDQpgYGB7cn0NCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhhcnJfZGVsYXkpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMTkNCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgOSAgICAgIDY0MSAgICAgICAgICAgIDkwMCAgICAgIDEzMDEgICAgIDEyNDINCiM+IDIgIDIwMTMgICAgIDYgICAgMTUgICAgIDE0MzIgICAgICAgICAgIDE5MzUgICAgICAxMTM3ICAgICAxNjA3DQojPiAzICAyMDEzICAgICAxICAgIDEwICAgICAxMTIxICAgICAgICAgICAxNjM1ICAgICAgMTEyNiAgICAgMTIzOQ0KIz4gNCAgMjAxMyAgICAgOSAgICAyMCAgICAgMTEzOSAgICAgICAgICAgMTg0NSAgICAgIDEwMTQgICAgIDE0NTcNCiM+IDUgIDIwMTMgICAgIDcgICAgMjIgICAgICA4NDUgICAgICAgICAgIDE2MDAgICAgICAxMDA1ICAgICAxMDQ0DQojPiA2ICAyMDEzICAgICA0ICAgIDEwICAgICAxMTAwICAgICAgICAgICAxOTAwICAgICAgIDk2MCAgICAgMTM0Mg0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisgyLHKp9a1vau74bG7t8XWw9Tayv2+3byvtcTEqc6yDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYyg1LCAyLCBOQSkpDQphcnJhbmdlKGRmLCB4KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMgocEgMQ0KIz4gICAgICAgeA0KIz4gICA8ZGJsPg0KIz4gMSAgICAgMg0KIz4gMiAgICAgNQ0KIz4gMyAgICBOQQ0KYGBgDQpgYGB7cn0NCmFycmFuZ2UoZGYsIGRlc2MoeCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMyChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgICA1DQojPiAyICAgICAyDQojPiAzICAgIE5BDQpgYGANCg0KIyA0INPDIGBzZWxlY3QoKWAgybjRocHQDQojIyA0LjEgu/mxvtPDt6gNCisg0aHU8XllYXKhom1vbnRooaJkYXnB0A0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDMNCiM+ICAgIHllYXIgbW9udGggICBkYXkNCiM+ICAgPGludD4gPGludD4gPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDENCiM+IDIgIDIwMTMgICAgIDEgICAgIDENCiM+IDMgIDIwMTMgICAgIDEgICAgIDENCiM+IDQgIDIwMTMgICAgIDEgICAgIDENCiM+IDUgIDIwMTMgICAgIDEgICAgIDENCiM+IDYgIDIwMTMgICAgIDEgICAgIDENCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisg0aHU8XllYXK6zWRhedauvOS1xMHQo6iw/MCoo6kNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIHllYXI6ZGF5KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMw0KIz4gICAgeWVhciBtb250aCAgIGRheQ0KIz4gICA8aW50PiA8aW50PiA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgMQ0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzDQpgYGANCg0KKyDRodTxs/15ZWFyus1kYXnWrrzktcTB0NLUzeK1xMv509DB0KOosPzAqKOpDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCAtKHllYXI6ZGF5KSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDE2DQojPiAgIGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZSBzY2hlZF9hcnJfdGltZSBhcnJfZGVsYXkNCiM+ICAgICAgPGludD4gICAgICAgICAgPGludD4gICAgIDxkYmw+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPg0KIz4gMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzAgICAgICAgICAgICA4MTkgICAgICAgIDExDQojPiAyICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MCAgICAgICAgICAgIDgzMCAgICAgICAgMjANCiM+IDMgICAgICA1NDIgICAgICAgICAgICA1NDAgICAgICAgICAyICAgICAgOTIzICAgICAgICAgICAgODUwICAgICAgICAzMw0KIz4gNCAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQgICAgICAgICAgIDEwMjIgICAgICAgLTE4DQojPiA1ICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMiAgICAgICAgICAgIDgzNyAgICAgICAtMjUNCiM+IDYgICAgICA1NTQgICAgICAgICAgICA1NTggICAgICAgIC00ICAgICAgNzQwICAgICAgICAgICAgNzI4ICAgICAgICAxMg0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTAgbW9yZSB2YXJpYWJsZXM6IGNhcnJpZXIgPGNocj4sDQojPiAjICAgZmxpZ2h0IDxpbnQ+LCB0YWlsbnVtIDxjaHI+LCBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LA0KIz4gIyAgIGRpc3RhbmNlIDxkYmw+LCBob3VyIDxkYmw+LCBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQojIyA0LjIgSGVscGVyIEZ1bmN0aW9ucw0KKyBgc3RhcnRzX3dpdGgoeCwgaWdub3JlLmNhc2UgPSBUUlVFKWA6IG5hbWVzIHN0YXJ0cyB3aXRoIHguICANCg0KKyBgZW5kc193aXRoKHgsIGlnbm9yZS5jYXNlID0gVFJVRSlgOiBuYW1lcyBlbmRzIGluIHguICANCg0KKyBgY29udGFpbnMoeCwgaWdub3JlLmNhc2UgPSBUUlVFKWA6IHNlbGVjdHMgYWxsIHZhcmlhYmxlcyB3aG9zZSBuYW1lIGNvbnRhaW5zIHguICANCg0KKyBgbWF0Y2hlcyh4LCBpZ25vcmUuY2FzZSA9IFRSVUUpYDogc2VsZWN0cyBhbGwgdmFyaWFibGVzIHdob3NlIG5hbWUgbWF0Y2hlcyB0aGUgcmVndWxhciBleHByZXNzaW9uIHguICANCg0KKyBgbnVtX3JhbmdlKCJ4IiwgMTo1LCB3aWR0aCA9IDIpYDogc2VsZWN0cyBhbGwgdmFyaWFibGVzIChudW1lcmljYWxseSkgZnJvbSB4MDEgdG8geDA1LiAgDQoNCisgYG9uZV9vZigieCIsICJ5IiwgInoiKWA6IHNlbGVjdHMgdmFyaWFibGVzIHByb3ZpZGVkIGluIGEgY2hhcmFjdGVyIHZlY3Rvci4gIA0KDQorIGBldmVyeXRoaW5nKClgOiBzZWxlY3RzIGFsbCB2YXJpYWJsZXMuDQoNCiMjIDQuMyDA+9PDIGBldmVyeXRoaW5nKClgIL2rwdDSxrW91+7HsMPmDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCB0aW1lX2hvdXIsIGFpcl90aW1lLCBldmVyeXRoaW5nKCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxOQ0KIz4gICAgICAgICAgICAgdGltZV9ob3VyIGFpcl90aW1lICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lDQojPiAgICAgICAgICAgICAgICA8ZHR0bT4gICAgPGRibD4gPGludD4gPGludD4gPGludD4gICAgPGludD4gICAgICAgICAgPGludD4NCiM+IDEgMjAxMy0wMS0wMSAwNTowMDowMCAgICAgIDIyNyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNQ0KIz4gMiAyMDEzLTAxLTAxIDA1OjAwOjAwICAgICAgMjI3ICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5DQojPiAzIDIwMTMtMDEtMDEgMDU6MDA6MDAgICAgICAxNjAgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDIgICAgICAgICAgICA1NDANCiM+IDQgMjAxMy0wMS0wMSAwNTowMDowMCAgICAgIDE4MyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NQ0KIz4gNSAyMDEzLTAxLTAxIDA2OjAwOjAwICAgICAgMTE2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwDQojPiA2IDIwMTMtMDEtMDEgMDU6MDA6MDAgICAgICAxNTAgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA1NTgNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBkZXBfZGVsYXkgPGRibD4sDQojPiAjICAgYXJyX3RpbWUgPGludD4sIHNjaGVkX2Fycl90aW1lIDxpbnQ+LCBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sDQojPiAjICAgZmxpZ2h0IDxpbnQ+LCB0YWlsbnVtIDxjaHI+LCBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGRpc3RhbmNlIDxkYmw+LA0KIz4gIyAgIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPg0KYGBgDQoNCiMjIDQuNCBgcmVuYW1lKClgILqvyv0NCmBgYHtyfQ0KcmVuYW1lKGZsaWdodHMsIHRhaWxfbnVtID0gdGFpbG51bSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA5MjMNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDQgICAgICAgICAgICA1NDUgICAgICAgIC0xICAgICAxMDA0DQojPiA1ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMg0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDU1OCAgICAgICAgLTQgICAgICA3NDANCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOg0KIz4gIyAgIHNjaGVkX2Fycl90aW1lIDxpbnQ+LCBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwNCiM+ICMgICB0YWlsX251bSA8Y2hyPiwgb3JpZ2luIDxjaHI+LCBkZXN0IDxjaHI+LCBhaXJfdGltZSA8ZGJsPiwNCiM+ICMgICBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwgbWludXRlIDxkYmw+LCB0aW1lX2hvdXIgPGR0dG0+DQpgYGANCg0KIyA1INPDIGBtdXRhdGUoKWAgzO2808HQDQojIyA1LjEgu/mxvtPDt6gNCisgttTS0dPQwdC9+NDQyv2+3dTLy+OyosztvNPOqtDCwdANCmBgYHtyfQ0KZmxpZ2h0c19zbWwgPC0gc2VsZWN0KGZsaWdodHMsIA0KICB5ZWFyOmRheSwgDQogIGVuZHNfd2l0aCgiZGVsYXkiKSwgDQogIGRpc3RhbmNlLCANCiAgYWlyX3RpbWUNCikNCg0KbXV0YXRlKGZsaWdodHNfc21sLA0KICBnYWluID0gYXJyX2RlbGF5IC0gZGVwX2RlbGF5LA0KICBzcGVlZCA9IGRpc3RhbmNlIC8gYWlyX3RpbWUgKiA2MA0KKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgOQ0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfZGVsYXkgYXJyX2RlbGF5IGRpc3RhbmNlIGFpcl90aW1lICBnYWluIHNwZWVkDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8ZGJsPiAgICAgPGRibD4gICAgPGRibD4gICAgPGRibD4gPGRibD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgICAyICAgICAgICAxMSAgICAgMTQwMCAgICAgIDIyNyAgICAgOSAgIDM3MA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgIDQgICAgICAgIDIwICAgICAxNDE2ICAgICAgMjI3ICAgIDE2ICAgMzc0DQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgICAgMiAgICAgICAgMzMgICAgIDEwODkgICAgICAxNjAgICAgMzEgICA0MDgNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICAgIC0xICAgICAgIC0xOCAgICAgMTU3NiAgICAgIDE4MyAgIC0xNyAgIDUxNw0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgLTYgICAgICAgLTI1ICAgICAgNzYyICAgICAgMTE2ICAgLTE5ICAgMzk0DQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgICAtNCAgICAgICAgMTIgICAgICA3MTkgICAgICAxNTAgICAgMTYgICAyODgNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisgv8nS1NTazazSu9PvvuTW0LbUuNXU9rzTtcTB0L340NCy2df3DQpgYGB7cn0NCm11dGF0ZShmbGlnaHRzX3NtbCwNCiAgZ2FpbiA9IGFycl9kZWxheSAtIGRlcF9kZWxheSwNCiAgaG91cnMgPSBhaXJfdGltZSAvIDYwLA0KICBnYWluX3Blcl9ob3VyID0gZ2FpbiAvIGhvdXJzDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxMA0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfZGVsYXkgYXJyX2RlbGF5IGRpc3RhbmNlIGFpcl90aW1lICBnYWluIGhvdXJzDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8ZGJsPiAgICAgPGRibD4gICAgPGRibD4gICAgPGRibD4gPGRibD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgICAyICAgICAgICAxMSAgICAgMTQwMCAgICAgIDIyNyAgICAgOSAgMy43OA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgIDQgICAgICAgIDIwICAgICAxNDE2ICAgICAgMjI3ICAgIDE2ICAzLjc4DQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgICAgMiAgICAgICAgMzMgICAgIDEwODkgICAgICAxNjAgICAgMzEgIDIuNjcNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICAgIC0xICAgICAgIC0xOCAgICAgMTU3NiAgICAgIDE4MyAgIC0xNyAgMy4wNQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgLTYgICAgICAgLTI1ICAgICAgNzYyICAgICAgMTE2ICAgLTE5ICAxLjkzDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgICAtNCAgICAgICAgMTIgICAgICA3MTkgICAgICAxNTAgICAgMTYgIDIuNTANCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEgbW9yZSB2YXJpYWJsZXM6IGdhaW5fcGVyX2hvdXIgPGRibD4NCmBgYA0KDQorINPDIGB0cmFuc211dGUoKWAgvfa99rGjwfTQwtT2tcTB0A0KYGBge3J9DQp0cmFuc211dGUoZmxpZ2h0cywNCiAgZ2FpbiA9IGFycl9kZWxheSAtIGRlcF9kZWxheSwNCiAgaG91cnMgPSBhaXJfdGltZSAvIDYwLA0KICBnYWluX3Blcl9ob3VyID0gZ2FpbiAvIGhvdXJzDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAzDQojPiAgICBnYWluIGhvdXJzIGdhaW5fcGVyX2hvdXINCiM+ICAgPGRibD4gPGRibD4gICAgICAgICA8ZGJsPg0KIz4gMSAgICAgOSAgMy43OCAgICAgICAgICAyLjM4DQojPiAyICAgIDE2ICAzLjc4ICAgICAgICAgIDQuMjMNCiM+IDMgICAgMzEgIDIuNjcgICAgICAgICAxMS42Mg0KIz4gNCAgIC0xNyAgMy4wNSAgICAgICAgIC01LjU3DQojPiA1ICAgLTE5ICAxLjkzICAgICAgICAgLTkuODMNCiM+IDYgICAgMTYgIDIuNTAgICAgICAgICAgNi40MA0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzDQpgYGANCg0KIyMgNS4yIL/J0tTTw9PavMbL49DCseTBv7XEz/LBv7uv1MvL47f7DQorIEFyaXRobWV0aWMgb3BlcmF0b3JzOiBgK2AsIGAtYCwgYCpgLCBgL2AsIGBeYC4NCg0KKyBNb2R1bGFyIGFyaXRobWV0aWM6IGAlLyVgIChpbnRlZ2VyIGRpdmlzaW9uKSBhbmQgYCUlYCAocmVtYWluZGVyKS4NCmBgYHtyfQ0KdHJhbnNtdXRlKGZsaWdodHMsDQogIGRlcF90aW1lLA0KICBob3VyID0gZGVwX3RpbWUgJS8lIDEwMCwNCiAgbWludXRlID0gZGVwX3RpbWUgJSUgMTAwDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAzDQojPiAgIGRlcF90aW1lICBob3VyIG1pbnV0ZQ0KIz4gICAgICA8aW50PiA8ZGJsPiAgPGRibD4NCiM+IDEgICAgICA1MTcgICAgIDUgICAgIDE3DQojPiAyICAgICAgNTMzICAgICA1ICAgICAzMw0KIz4gMyAgICAgIDU0MiAgICAgNSAgICAgNDINCiM+IDQgICAgICA1NDQgICAgIDUgICAgIDQ0DQojPiA1ICAgICAgNTU0ICAgICA1ICAgICA1NA0KIz4gNiAgICAgIDU1NCAgICAgNSAgICAgNTQNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisgTG9nczogYGxvZygpYCwgYGxvZzIoKWAsIGBsb2cxMCgpYC4gDQoNCisgT2Zmc2V0czogYGxlYWQoKWAgYW5kIGBsYWcoKWAgYWxsb3cgeW91IHRvIHJlZmVyIHRvIGxlYWRpbmcgb3IgbGFnZ2luZyB2YWx1ZXMuDQpgYGB7cn0NCih4IDwtIDE6MTApDQpgYGANCmBgYHtyfQ0KbGFnKHgpDQpgYGANCmBgYHtyfQ0KbGVhZCh4KQ0KYGBgDQpgYGB7cn0NCiMgY29tcHV0ZSBydW5uaW5nIGRpZmZlcmVuY2VzDQp4IC0gbGFnKHgpDQpgYGANCmBgYHtyfQ0KIyBmaW5kIHdoZW4gdmFsdWVzIGNoYW5nZQ0KeCAhPSBsYWcoeCkNCmBgYA0KDQorIEN1bXVsYXRpdmUgYW5kIHJvbGxpbmcgYWdncmVnYXRlczogYGN1bXN1bSgpYCwgYGN1bXByb2QoKWAsIGBjdW1taW4oKWAsIGBjdW1tYXgoKWAsIGBjdW1tZWFuKClgLiAgDQpJZiB5b3UgbmVlZCByb2xsaW5nIGFnZ3JlZ2F0ZXMgKGkuZS4gYSBzdW0gY29tcHV0ZWQgb3ZlciBhIHJvbGxpbmcgd2luZG93KSwgdHJ5IHRoZSBgUmNwcFJvbGxgIHBhY2thZ2UuDQpgYGB7cn0NCngNCmBgYA0KYGBge3J9DQpjdW1zdW0oeCkNCmBgYA0KYGBge3J9DQpjdW1tZWFuKHgpDQpgYGANCg0KKyBMb2dpY2FsIGNvbXBhcmlzb25zLCBgPGAsIGA8PWAsIGA+YCwgYD49YCwgYCE9YC4NCg0KKyBSYW5raW5nOiBgbWluX3JhbmsoKWAsIGByb3dfbnVtYmVyKClgLCBgZGVuc2VfcmFuaygpYCwgYHBlcmNlbnRfcmFuaygpYCwgYGN1bWVfZGlzdCgpYCwgYG50aWxlKClgLg0KYGBge3J9DQooeSA8LSBjKDEsIDIsIDIsIE5BLCAzLCA0KSkNCmBgYA0KYGBge3J9DQptaW5fcmFuayh5KQ0KYGBgDQpgYGB7cn0NCm1pbl9yYW5rKGRlc2MoeSkpDQpgYGANCmBgYHtyfQ0Kcm93X251bWJlcih5KQ0KYGBgDQpgYGB7cn0NCmRlbnNlX3JhbmsoeSkNCmBgYA0KYGBge3J9DQpwZXJjZW50X3JhbmsoeSkNCmBgYA0KYGBge3J9DQpjdW1lX2Rpc3QoeSkNCmBgYA0KDQojIDYg08MgYHN1bW1hcmlzZSgpYCC8xsvjt9bX6c2zvMbBvw0KIyMgNi4xIGBncm91cF9ieSgpYCC6zSBgc3VtbWFyaXNlKClgIMGqus/KudPDo6y8xsvjt9bX6c2zvMbBvw0KYGBge3J9DQpzdW1tYXJpc2UoZmxpZ2h0cywgZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAxIKHBIDENCiM+ICAgZGVsYXkNCiM+ICAgPGRibD4NCiM+IDEgIDEyLjYNCmBgYA0KDQpgYGB7cn0NCmJ5X2RheSA8LSBncm91cF9ieShmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQ0Kc3VtbWFyaXNlKGJ5X2RheSwgZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlbGF5DQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+IDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxIDExLjU1DQojPiAyICAyMDEzICAgICAxICAgICAyIDEzLjg2DQojPiAzICAyMDEzICAgICAxICAgICAzIDEwLjk5DQojPiA0ICAyMDEzICAgICAxICAgICA0ICA4Ljk1DQojPiA1ICAyMDEzICAgICAxICAgICA1ICA1LjczDQojPiA2ICAyMDEzICAgICAxICAgICA2ICA3LjE1DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KDQojIyA2LjIgudy1wLLZ1/e3+yBgJT4lYA0KKyDMvcv3ttTT2rK7zay12LXjo6zGvb75t8nQ0L7gwOvT68a9vvnR087zyrG85NauvOS1xLnYz7Who7/J0tS3os/Wo6zGvb75t8nQ0L7gwOvOqjc1MNOiwO/KsaOsxr2++dHTzvPKsbzktO+1vbfl1rWjrL/JxNzKx9PJ09q4/LOktcS3ydDQvuDA66OszqrD1rK50dPO88zhuanBy7/JxNyhow0KYGBge3J9DQpieV9kZXN0IDwtIGdyb3VwX2J5KGZsaWdodHMsIGRlc3QpDQoNCmRlbGF5IDwtIHN1bW1hcmlzZShieV9kZXN0LA0KICBjb3VudCA9IG4oKSwNCiAgZGlzdCA9IG1lYW4oZGlzdGFuY2UsIG5hLnJtID0gVFJVRSksDQogIGRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkNCikNCg0KKGRlbGF5IDwtIGZpbHRlcihkZWxheSwgY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogOTYgocEgNA0KIz4gICAgIGRlc3QgY291bnQgICAgICBkaXN0ICAgICBkZWxheQ0KIz4gICAgPGNocj4gPGludD4gICAgIDxkYmw+ICAgICA8ZGJsPg0KIz4gMSAgICBBQlEgICAyNTQgMTgyNi4wMDAwICA0LjM4MTg5MA0KIz4gMiAgICBBQ0sgICAyNjUgIDE5OS4wMDAwICA0Ljg1MjI3Mw0KIz4gMyAgICBBTEIgICA0MzkgIDE0My4wMDAwIDE0LjM5NzEyOQ0KIz4gNCAgICBBVEwgMTcyMTUgIDc1Ny4xMDgyIDExLjMwMDExMw0KIz4gNSAgICBBVVMgIDI0MzkgMTUxNC4yNTMwICA2LjAxOTkwOQ0KIz4gNiAgICBBVkwgICAyNzUgIDU4My41ODE4ICA4LjAwMzgzMQ0KIz4gNyAgICBCREwgICA0NDMgIDExNi4wMDAwICA3LjA0ODU0NA0KIz4gOCAgICBCR1IgICAzNzUgIDM3OC4wMDAwICA4LjAyNzkzMw0KIz4gOSAgICBCSE0gICAyOTcgIDg2NS45OTY2IDE2Ljg3NzMyMw0KIz4gMTAgICBCTkEgIDYzMzMgIDc1OC4yMTM1IDExLjgxMjQ1OQ0KIz4gIyAuLi4gd2l0aCA4NiBtb3JlIHJvd3MNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRlbGF5LCBtYXBwaW5nID0gYWVzKHggPSBkaXN0LCB5ID0gZGVsYXkpKSArDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBjb3VudCksIGFscGhhID0gMS8zKSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpDQpgYGANCg0KKyDK/b7d1KS0psDtyea8sDO49rK91uijug0KICAgICsg0sC+3cS/tcS12LfW1+kNCiAgICArILzGy+O31tfpuvO1xMa9vvm3ydDQvuDA66Gixr2++dHTzvPKsbzkus26vbDgyv0NCiAgICArILn9wsu19M/Ezf7SxLv6s6GjqMa9vvm3ydDQvuDA68rHxuTL+7v6s6G1xDKxttLUyc+jqbrNur2w4Mr9uf3J2bXExL+1xLXYDQoNCg0KKyDKudPDudy1wLLZ1/e3+yBgJT4lYCDN6rPJ0tTJzzO49rK91ugNCmBgYHtyfQ0KZGVsYXlzIDwtIGZsaWdodHMgJT4lIA0KICBncm91cF9ieShkZXN0KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBjb3VudCA9IG4oKSwNCiAgICBkaXN0ID0gbWVhbihkaXN0YW5jZSwgbmEucm0gPSBUUlVFKSwNCiAgICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpDQogICkgJT4lIA0KICBmaWx0ZXIoY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikNCmBgYA0KDQojIyA2LjMgyLHKp9a1DQorIMixyqfWtbSryOu+27rPuq/K/aOs0rK74be1u9jIscqn1rUNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGRlcF9kZWxheSkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSAgbWVhbg0KIz4gICA8aW50PiA8aW50PiA8aW50PiA8ZGJsPg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICBOQQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICBOQQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICBOQQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICBOQQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICBOQQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICBOQQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCisgyrnTwyBgbmEucm1gILLOyv0NCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5ICBtZWFuDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+IDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxIDExLjU1DQojPiAyICAyMDEzICAgICAxICAgICAyIDEzLjg2DQojPiAzICAyMDEzICAgICAxICAgICAzIDEwLjk5DQojPiA0ICAyMDEzICAgICAxICAgICA0ICA4Ljk1DQojPiA1ICAyMDEzICAgICAxICAgICA1ICA1LjczDQojPiA2ICAyMDEzICAgICAxICAgICA2ICA3LjE1DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KKyDPyNDQzN6z/SBgTkFgINa1DQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgPC0gZmxpZ2h0cyAlPiUgDQogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSwgIWlzLm5hKGFycl9kZWxheSkpDQoNCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuID0gbWVhbihkZXBfZGVsYXkpKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMzY1IHggNF0NCiM+IEdyb3VwczogeWVhciwgbW9udGggWz9dDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgIG1lYW4NCiM+ICAgPGludD4gPGludD4gPGludD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgMTEuNDQNCiM+IDIgIDIwMTMgICAgIDEgICAgIDIgMTMuNjgNCiM+IDMgIDIwMTMgICAgIDEgICAgIDMgMTAuOTENCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgIDguOTcNCiM+IDUgIDIwMTMgICAgIDEgICAgIDUgIDUuNzMNCiM+IDYgIDIwMTMgICAgIDEgICAgIDYgIDcuMTUNCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQojIyA2LjQgvMbK/aOoYGNvdW50YKOpDQrU2rzGy+O31tfpzbO8xsG/tcTKsbryo6zQ6NKqv7zCx9fpxNrR+bG+tcS49sr9o6hgbigpYKOpoaK3x8ixyqfWtbXEuPbK/aOoYHN1bSghaXMubmEoeCkpYKOp0tS8sLfW1+m1xLj2yv0gIA0KDQorINPDIGB0YWlsbnVtYCDH+LfWt8m7+qOs08O6y8PctsjNvLfWzva3ybv6tcTGvb750dPO88qxvOS31rK8x+m/9g0KYGBge3J9DQpkZWxheXMgPC0gbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHRhaWxudW0pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXkpDQogICkNCg0KZGVsYXlzDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogNCwwMzcgocEgMg0KIz4gICAgdGFpbG51bSAgICAgIGRlbGF5DQojPiAgICAgIDxjaHI+ICAgICAgPGRibD4NCiM+IDEgICBEOTQyRE4gMzEuNTAwMDAwMA0KIz4gMiAgIE4wRUdNUSAgOS45ODI5NTQ1DQojPiAzICAgTjEwMTU2IDEyLjcxNzI0MTQNCiM+IDQgICBOMTAyVVcgIDIuOTM3NTAwMA0KIz4gNSAgIE4xMDNVUyAtNi45MzQ3ODI2DQojPiA2ICAgTjEwNFVXICAxLjgwNDM0NzgNCiM+IDcgICBOMTA1NzUgMjAuNjkxNDQ5OA0KIz4gOCAgIE4xMDVVVyAtMC4yNjY2NjY3DQojPiA5ICAgTjEwN1VTIC01LjczMTcwNzMNCiM+IDEwICBOMTA4VVcgLTEuMjUwMDAwMA0KIz4gIyAuLi4gd2l0aCA0LDAyNyBtb3JlIHJvd3MNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRlbGF5cywgbWFwcGluZyA9IGFlcyh4ID0gZGVsYXkpKSArIA0KICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTApDQpgYGANCg0KKyDTwyBgbigpYCC8xsvj1+nE2tH5sb649sr9o6y008mitePNvL/J0tS/tLP2o6y3ydDQtM7K/cnZtcS3ybv6o6zGvb750dPO88qxvOS1xLHk0uyzzLbIuPy08w0KYGBge3J9DQpkZWxheXMgPC0gbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHRhaWxudW0pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSksDQogICAgbiA9IG4oKQ0KICApDQoNCmRlbGF5cw0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDQsMDM3IKHBIDMNCiM+ICAgIHRhaWxudW0gICAgICBkZWxheSAgICAgbg0KIz4gICAgICA8Y2hyPiAgICAgIDxkYmw+IDxpbnQ+DQojPiAxICAgRDk0MkROIDMxLjUwMDAwMDAgICAgIDQNCiM+IDIgICBOMEVHTVEgIDkuOTgyOTU0NSAgIDM1Mg0KIz4gMyAgIE4xMDE1NiAxMi43MTcyNDE0ICAgMTQ1DQojPiA0ICAgTjEwMlVXICAyLjkzNzUwMDAgICAgNDgNCiM+IDUgICBOMTAzVVMgLTYuOTM0NzgyNiAgICA0Ng0KIz4gNiAgIE4xMDRVVyAgMS44MDQzNDc4ICAgIDQ2DQojPiA3ICAgTjEwNTc1IDIwLjY5MTQ0OTggICAyNjkNCiM+IDggICBOMTA1VVcgLTAuMjY2NjY2NyAgICA0NQ0KIz4gOSAgIE4xMDdVUyAtNS43MzE3MDczICAgIDQxDQojPiAxMCAgTjEwOFVXIC0xLjI1MDAwMDAgICAgNjANCiM+ICMgLi4uIHdpdGggNCwwMjcgbW9yZSByb3dzDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkZWxheXMsIG1hcHBpbmcgPSBhZXMoeCA9IG4sIHkgPSBkZWxheSkpICsgDQogIGdlb21fcG9pbnQoYWxwaGEgPSAxLzEwKQ0KYGBgDQoNCisgwPvTwyBgZmlsdGVyKClgIMm40aGz9rfJ0NC0zsr9tPPT2jI1tcS3ybv6o6y31s72y/zDx7XE0dPO88fpv/YNCmBgYHtyfQ0KZGVsYXlzICU+JSANCiAgZmlsdGVyKG4gPiAyNSkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gbiwgeSA9IGRlbGF5KSkgKyANCiAgICBnZW9tX3BvaW50KGFscGhhID0gMS8xMCkNCmBgYA0KDQorIGBiYWAgtPqx7bv3tPKzybmmwsqjrCBgYWJgILT6se2797TytM7K/aOsu/e08rPJuabCytPru/e08sr91f3P4LnYo6y/ycTcysfS8s6qx/K208fjz/LT2sjDs8m5psLKuN+1xMfy1LHTtdPQuPy24LP2s6G7+rvhDQpgYGB7cn0NCiMgQ29udmVydCB0byBhIHRpYmJsZSBzbyBpdCBwcmludHMgbmljZWx5DQpiYXR0aW5nIDwtIGFzX3RpYmJsZShMYWhtYW46OkJhdHRpbmcpDQoNCmJhdHRlcnMgPC0gYmF0dGluZyAlPiUgDQogIGdyb3VwX2J5KHBsYXllcklEKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBiYSA9IHN1bShILCBuYS5ybSA9IFRSVUUpIC8gc3VtKEFCLCBuYS5ybSA9IFRSVUUpLA0KICAgIGFiID0gc3VtKEFCLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KYmF0dGVycyAlPiUgDQogIGZpbHRlcihhYiA+IDEwMCkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gYWIsIHkgPSBiYSkpICsNCiAgICBnZW9tX3BvaW50KCkgKyANCiAgICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQ0KYGBgDQoNCisg0sC+3SBgYmFgIL340NC9tdDyxcXB0KOsv8nS1L+0s/ajrLv3tPKzybmmwsrX7rjftcTH8tSxo6y797TytM7K/da709DSu7TOo6y0v7TiysfTydPa1MvG+Lb4t8e8vMr1DQpgYGB7cn0NCmJhdHRlcnMgJT4lIA0KICBhcnJhbmdlKGRlc2MoYmEpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDE4LDY1OSChwSAzDQojPiAgICBwbGF5ZXJJRCAgICBiYSAgICBhYg0KIz4gICAgICAgPGNocj4gPGRibD4gPGludD4NCiM+IDEgYWJyYW1nZTAxICAgICAxICAgICAxDQojPiAyIGJhbmlzamUwMSAgICAgMSAgICAgMQ0KIz4gMyBiYXJ0b2NsMDEgICAgIDEgICAgIDENCiM+IDQgIGJhc3NkbzAxICAgICAxICAgICAxDQojPiA1IGJpcmFzc3QwMSAgICAgMSAgICAgMg0KIz4gNiBicnVuZWp1MDEgICAgIDEgICAgIDENCiM+ICMgLi4uIHdpdGggMS44NjVlKzA0IG1vcmUgcm93cw0KYGBgDQoNCiMjIDYuNSC+27rPzbO8xrqvyv0NCisgTWVhc3VyZXMgb2YgbG9jYXRpb246IGBtZWFuKHgpYCwgYG1lZGlhbih4KWAuDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBhdmdfZGVsYXkxID0gbWVhbihhcnJfZGVsYXkpLA0KICAgIGF2Z19kZWxheTIgPSBtZWFuKGFycl9kZWxheVthcnJfZGVsYXkgPiAwXSkgIyB0aGUgYXZlcmFnZSBwb3NpdGl2ZSBkZWxheQ0KICApDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA1XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBhdmdfZGVsYXkxIGF2Z19kZWxheTINCiM+ICAgPGludD4gPGludD4gPGludD4gICAgICA8ZGJsPiAgICAgIDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgMTIuNjUgICAgICAgMzIuNQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgIDEyLjY5ICAgICAgIDMyLjANCiM+IDMgIDIwMTMgICAgIDEgICAgIDMgICAgICAgNS43MyAgICAgICAyNy43DQojPiA0ICAyMDEzICAgICAxICAgICA0ICAgICAgLTEuOTMgICAgICAgMjguMw0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgIC0xLjUzICAgICAgIDIyLjYNCiM+IDYgIDIwMTMgICAgIDEgICAgIDYgICAgICAgNC4yNCAgICAgICAyNC40DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KDQorIE1lYXN1cmVzIG9mIHNwcmVhZDogYHNkKHgpYCwgYElRUih4KWAsIGBtYWQoeClgLg0KYGBge3J9DQojIFdoeSBpcyBkaXN0YW5jZSB0byBzb21lIGRlc3RpbmF0aW9ucyBtb3JlIHZhcmlhYmxlIHRoYW4gdG8gb3RoZXJzPw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KGRlc3QpICU+JSANCiAgc3VtbWFyaXNlKGRpc3RhbmNlX3NkID0gc2QoZGlzdGFuY2UpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhkaXN0YW5jZV9zZCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMTA0IKHBIDINCiM+ICAgIGRlc3QgZGlzdGFuY2Vfc2QNCiM+ICAgPGNocj4gICAgICAgPGRibD4NCiM+IDEgICBFR0UgICAgICAgMTAuNTQNCiM+IDIgICBTQU4gICAgICAgMTAuMzUNCiM+IDMgICBTRk8gICAgICAgMTAuMjINCiM+IDQgICBITkwgICAgICAgMTAuMDANCiM+IDUgICBTRUEgICAgICAgIDkuOTgNCiM+IDYgICBMQVMgICAgICAgIDkuOTENCiM+ICMgLi4uIHdpdGggOTggbW9yZSByb3dzDQpgYGANCisgTWVhc3VyZXMgb2YgcmFuazogYG1pbih4KWAsIGBxdWFudGlsZSh4LCAwLjI1KWAsIGBtYXgoeClgLiANCmBgYHtyfQ0KIyBXaGVuIGRvIHRoZSBmaXJzdCBhbmQgbGFzdCBmbGlnaHRzIGxlYXZlIGVhY2ggZGF5Pw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGZpcnN0ID0gbWluKGRlcF90aW1lKSwNCiAgICBsYXN0ID0gbWF4KGRlcF90aW1lKQ0KICApDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA1XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBmaXJzdCAgbGFzdA0KIz4gICA8aW50PiA8aW50PiA8aW50PiA8aW50PiA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgIDUxNyAgMjM1Ng0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICA0MiAgMjM1NA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICAzMiAgMjM0OQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICAyNSAgMjM1OA0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAxNCAgMjM1Nw0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICAxNiAgMjM1NQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCg0KKyBNZWFzdXJlcyBvZiBwb3NpdGlvbjogYGZpcnN0KHgpYCwgYG50aCh4LCAyKWAsIGBsYXN0KHgpYC4gDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBmaXJzdF9kZXAgPSBmaXJzdChkZXBfdGltZSksIA0KICAgIGxhc3RfZGVwID0gbGFzdChkZXBfdGltZSkNCiAgKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMzY1IHggNV0NCiM+IEdyb3VwczogeWVhciwgbW9udGggWz9dDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZmlyc3RfZGVwIGxhc3RfZGVwDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8aW50PiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgICA1MTcgICAgIDIzNTYNCiM+IDIgIDIwMTMgICAgIDEgICAgIDIgICAgICAgIDQyICAgICAyMzU0DQojPiAzICAyMDEzICAgICAxICAgICAzICAgICAgICAzMiAgICAgMjM0OQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICAgICAgMjUgICAgIDIzNTgNCiM+IDUgIDIwMTMgICAgIDEgICAgIDUgICAgICAgIDE0ICAgICAyMzU3DQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICAgICAxNiAgICAgMjM1NQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCg0KzazR+bXE0Ke5+6Osv8nS1M2ouf3S1M/Ct723qMq1z9ajrLKix9K74bGjwfTL+dPQtcSx5MG/o6zXotLiIGBtdXRhdGUoKWAsIGBtaW5fcmFua2AsIGBmaWx0ZXIoKWAg1NrV4sDvtcTX99PDDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIG11dGF0ZShyID0gbWluX3JhbmsoZGVzYyhkZXBfdGltZSkpKSAlPiUgDQogIGZpbHRlcihyICVpbiUgcmFuZ2UocikpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFs3NzAgeCAyMF0NCiM+IEdyb3VwczogeWVhciwgbW9udGgsIGRheSBbMzY1XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAyMzU2ICAgICAgICAgICAyMzU5ICAgICAgICAtMyAgICAgIDQyNQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMiAgICAgICA0MiAgICAgICAgICAgMjM1OSAgICAgICAgNDMgICAgICA1MTgNCiM+IDQgIDIwMTMgICAgIDEgICAgIDIgICAgIDIzNTQgICAgICAgICAgIDIzNTkgICAgICAgIC01ICAgICAgNDEzDQojPiA1ICAyMDEzICAgICAxICAgICAzICAgICAgIDMyICAgICAgICAgICAyMzU5ICAgICAgICAzMyAgICAgIDUwNA0KIz4gNiAgMjAxMyAgICAgMSAgICAgMyAgICAgMjM0OSAgICAgICAgICAgMjM1OSAgICAgICAtMTAgICAgICA0MzQNCiM+ICMgLi4uIHdpdGggNzY0IG1vcmUgcm93cywgYW5kIDEzIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4sIHIgPGludD4NCmBgYA0KDQorIENvdW50czogYGNvdW50KClgLCBgbigpYCwgYHN1bSghaXMubmEoeCkpYCwgYG5fZGlzdGluY3QoeClgLg0KYGBge3J9DQojIFdoaWNoIGRlc3RpbmF0aW9ucyBoYXZlIHRoZSBtb3N0IGNhcnJpZXJzPw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KGRlc3QpICU+JSANCiAgc3VtbWFyaXNlKGNhcnJpZXJzID0gbl9kaXN0aW5jdChjYXJyaWVyKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoY2FycmllcnMpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEwNCChwSAyDQojPiAgICBkZXN0IGNhcnJpZXJzDQojPiAgIDxjaHI+ICAgIDxpbnQ+DQojPiAxICAgQVRMICAgICAgICA3DQojPiAyICAgQk9TICAgICAgICA3DQojPiAzICAgQ0xUICAgICAgICA3DQojPiA0ICAgT1JEICAgICAgICA3DQojPiA1ICAgVFBBICAgICAgICA3DQojPiA2ICAgQVVTICAgICAgICA2DQojPiAjIC4uLiB3aXRoIDk4IG1vcmUgcm93cw0KYGBgDQoNCse/tPO1xCBgY291bnQoKWAguq/K/aOstMu0przGy+PDv7j2u/qzodf3zqrEv7XEtdi1xLq9sODK/Q0KYGBge3J9DQpub3RfY2FuY2VsbGVkICU+JSANCiAgY291bnQoZGVzdCkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAxMDQgocEgMg0KIz4gICAgZGVzdCAgICAgbg0KIz4gICA8Y2hyPiA8aW50Pg0KIz4gMSAgIEFCUSAgIDI1NA0KIz4gMiAgIEFDSyAgIDI2NA0KIz4gMyAgIEFMQiAgIDQxOA0KIz4gNCAgIEFOQyAgICAgOA0KIz4gNSAgIEFUTCAxNjgzNw0KIz4gNiAgIEFVUyAgMjQxMQ0KIz4gIyAuLi4gd2l0aCA5OCBtb3JlIHJvd3MNCmBgYA0KDQpgY291bnQoKWAgv8nS1NPD09q808iovMbK/aOstMu0przGy+PDv7zct8m7+rXE19y3ydDQwO+zzA0KYGBge3J9DQpub3RfY2FuY2VsbGVkICU+JSANCiAgY291bnQodGFpbG51bSwgd3QgPSBkaXN0YW5jZSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiA0LDAzNyChwSAyDQojPiAgIHRhaWxudW0gICAgICBuDQojPiAgICAgPGNocj4gIDxkYmw+DQojPiAxICBEOTQyRE4gICAzNDE4DQojPiAyICBOMEVHTVEgMjM5MTQzDQojPiAzICBOMTAxNTYgMTA5NjY0DQojPiA0ICBOMTAyVVcgIDI1NzIyDQojPiA1ICBOMTAzVVMgIDI0NjE5DQojPiA2ICBOMTA0VVcgIDI0NjE2DQojPiAjIC4uLiB3aXRoIDQsMDMxIG1vcmUgcm93cw0KYGBgDQoNCisgQ291bnRzIGFuZCBwcm9wb3J0aW9ucyBvZiBsb2dpY2FsIHZhbHVlczogYHN1bSh4ID4gMTApYCwgYG1lYW4oeSA9PSAwKWAuIGBzdW0oeClgIGdpdmVzIHRoZSBudW1iZXIgb2YgYFRSVUVzYCBpbiBgeGAsIGFuZCBgbWVhbih4KWAgZ2l2ZXMgdGhlIHByb3BvcnRpb24uDQpgYGB7cn0NCiMgSG93IG1hbnkgZmxpZ2h0cyBsZWZ0IGJlZm9yZSA1YW0/ICh0aGVzZSB1c3VhbGx5IGluZGljYXRlIGRlbGF5ZWQNCiMgZmxpZ2h0cyBmcm9tIHRoZSBwcmV2aW91cyBkYXkpDQpub3RfY2FuY2VsbGVkICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgbW9udGgsIGRheSkgJT4lIA0KICBzdW1tYXJpc2Uobl9lYXJseSA9IHN1bShkZXBfdGltZSA8IDUwMCkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBuX2Vhcmx5DQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgICAzDQojPiAzICAyMDEzICAgICAxICAgICAzICAgICAgIDQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgICAgMw0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgICAzDQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICAgIDINCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCmBgYHtyfQ0KIyBXaGF0IHByb3BvcnRpb24gb2YgZmxpZ2h0cyBhcmUgZGVsYXllZCBieSBtb3JlIHRoYW4gYW4gaG91cj8NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZShob3VyX3BlcmMgPSBtZWFuKGFycl9kZWxheSA+IDYwKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGhvdXJfcGVyYw0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICAgPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgMC4wNzIyDQojPiAyICAyMDEzICAgICAxICAgICAyICAgIDAuMDg1MQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICAwLjA1NjcNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgMC4wMzk2DQojPiA1ICAyMDEzICAgICAxICAgICA1ICAgIDAuMDM0OQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICAwLjA0NzANCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCiMjIDYuNiDSwL7dtuC49rHkwb+9+NDQt9bX6Q0KtLS9qNLAvt224Lj2seTBv7XEt9bX6brzo6zDv9K7tM4gYHN1bW1hcmlzZWC2vLvhsP7A69K7suO31tfpseTBvyAgDQoNCisg0sC+3WB5ZWFyYCwgYG1vbnRoYCwgYGRheWAgyP249rHkwb+31tfpDQpgYGB7cn0NCmRhaWx5IDwtIGdyb3VwX2J5KGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpDQoocGVyX2RheSAgIDwtIHN1bW1hcmlzZShkYWlseSwgZmxpZ2h0cyA9IG4oKSkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBmbGlnaHRzDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgIDg0Mg0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgOTQzDQojPiAzICAyMDEzICAgICAxICAgICAzICAgICA5MTQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgIDkxNQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgNzIwDQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICA4MzINCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCisgYHN1bW1hcmlzZWAguvOjrLD+wOsgYGRheWAgseTBvw0KYGBge3J9DQoocGVyX21vbnRoIDwtIHN1bW1hcmlzZShwZXJfZGF5LCBmbGlnaHRzID0gc3VtKGZsaWdodHMpKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzEyIHggM10NCiM+IEdyb3VwczogeWVhciBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCBmbGlnaHRzDQojPiAgIDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAyNzAwNA0KIz4gMiAgMjAxMyAgICAgMiAgIDI0OTUxDQojPiAzICAyMDEzICAgICAzICAgMjg4MzQNCiM+IDQgIDIwMTMgICAgIDQgICAyODMzMA0KIz4gNSAgMjAxMyAgICAgNSAgIDI4Nzk2DQojPiA2ICAyMDEzICAgICA2ICAgMjgyNDMNCiM+ICMgLi4uIHdpdGggNiBtb3JlIHJvd3MNCmBgYA0KDQorIGBzdW1tYXJpc2VgILrzo6yw/sDrIGBtb250aGAgseTBvw0KYGBge3J9DQoocGVyX3llYXIgIDwtIHN1bW1hcmlzZShwZXJfbW9udGgsIGZsaWdodHMgPSBzdW0oZmxpZ2h0cykpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEgocEgMg0KIz4gICAgeWVhciBmbGlnaHRzDQojPiAgIDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgIDMzNjc3Ng0KYGBgDQoNCiMjIDYuNyDIoc/7t9bX6Q0KYGBge3J9DQpkYWlseSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgIyBubyBsb25nZXIgZ3JvdXBlZCBieSBkYXRlDQogIHN1bW1hcmlzZShmbGlnaHRzID0gbigpKSAgIyBhbGwgZmxpZ2h0cw0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEgocEgMQ0KIz4gICBmbGlnaHRzDQojPiAgICAgPGludD4NCiM+IDEgIDMzNjc3Ng0KYGBgDQoNCiMgNyC31tfpseS7u6OoYG11dGF0ZSgpYCwgYGZpbHRlcigpYKOpDQorINXSs/bDv7j2t9bX6dbQx+m/9tfusu61xLPJ1LENCmBgYHtyfQ0KZmxpZ2h0c19zbWwgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUNCiAgZmlsdGVyKHJhbmsoZGVzYyhhcnJfZGVsYXkpKSA8IDEwKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMywzMDYgeCA3XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCwgZGF5IFszNjVdDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX2RlbGF5IGFycl9kZWxheSBkaXN0YW5jZSBhaXJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICAgPGRibD4gICAgIDxkYmw+ICAgIDxkYmw+ICAgIDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgIDg1MyAgICAgICA4NTEgICAgICAxODQgICAgICAgNDENCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMjkwICAgICAgIDMzOCAgICAgMTEzNCAgICAgIDIxMw0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgICAyNjAgICAgICAgMjYzICAgICAgMjY2ICAgICAgIDQ2DQojPiA0ICAyMDEzICAgICAxICAgICAxICAgICAgIDE1NyAgICAgICAxNzQgICAgICAyMTMgICAgICAgNjANCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMjE2ICAgICAgIDIyMiAgICAgIDcwOCAgICAgIDEyMQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAyNTUgICAgICAgMjUwICAgICAgNTg5ICAgICAgMTE1DQojPiAjIC4uLiB3aXRoIDMsMzAwIG1vcmUgcm93cw0KYGBgDQoNCisg1dKz9sL61+PSu7aozPW8/rXE1+mx8A0KYGBge3J9DQpwb3B1bGFyX2Rlc3RzIDwtIGZsaWdodHMgJT4lIA0KICBncm91cF9ieShkZXN0KSAlPiUgDQogIGZpbHRlcihuKCkgPiAzNjUpDQoNCnBvcHVsYXJfZGVzdHMNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzMzMiw1NzcgeCAxOV0NCiM+IEdyb3VwczogZGVzdCBbNzddDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzANCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MzMgICAgICAgICAgICA1MjkgICAgICAgICA0ICAgICAgODUwDQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgNTQyICAgICAgICAgICAgNTQwICAgICAgICAgMiAgICAgIDkyMw0KIz4gNCAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA2MDAgICAgICAgIC02ICAgICAgODEyDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNTU4ICAgICAgICAtNCAgICAgIDc0MA0KIz4gIyAuLi4gd2l0aCAzLjMyNmUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisgt9bX6bzGy+PNs7zGwb8NCmBgYHtyfQ0KcG9wdWxhcl9kZXN0cyAlPiUgDQogIGZpbHRlcihhcnJfZGVsYXkgPiAwKSAlPiUgDQogIG11dGF0ZShwcm9wX2RlbGF5ID0gYXJyX2RlbGF5IC8gc3VtKGFycl9kZWxheSkpICU+JSANCiAgc2VsZWN0KHllYXI6ZGF5LCBkZXN0LCBhcnJfZGVsYXksIHByb3BfZGVsYXkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFsxMzEsMTA2IHggNl0NCiM+IEdyb3VwczogZGVzdCBbNzddDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgIGRlc3QgYXJyX2RlbGF5IHByb3BfZGVsYXkNCiM+ICAgPGludD4gPGludD4gPGludD4gPGNocj4gICAgIDxkYmw+ICAgICAgPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICBJQUggICAgICAgIDExICAgMS4xMWUtMDQNCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICBJQUggICAgICAgIDIwICAgMi4wMWUtMDQNCiM+IDMgIDIwMTMgICAgIDEgICAgIDEgICBNSUEgICAgICAgIDMzICAgMi4zNWUtMDQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICBPUkQgICAgICAgIDEyICAgNC4yNGUtMDUNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICBGTEwgICAgICAgIDE5ICAgOS4zOGUtMDUNCiM+IDYgIDIwMTMgICAgIDEgICAgIDEgICBPUkQgICAgICAgICA4ICAgMi44M2UtMDUNCiM+ICMgLi4uIHdpdGggMS4zMTFlKzA1IG1vcmUgcm93cw0KYGBg